/*
 *    Copyright (c) 2018-2025, lengleng All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: lengleng (wangiegie@gmail.com)
 */
package com.pig4cloud.pig.ads.service.impl;

import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dy.sdk.client.DyGdtClient;
import com.dy.sdk.client.DyKsClient;
import com.dy.sdk.client.DyTtClient;
import com.dy.sdk.model.request.ks.KsVideoUpdateRequest;
import com.dy.sdk.model.request.tt.TtVideoUpdateRequest;
import com.dy.sdk.model.request.tt.VideoUpdate;
import com.dy.yunying.api.entity.ParentGameDO;
import com.dy.yunying.api.feign.RemotePGameService;
import com.dy.yunying.api.req.ParentGameReq;
import com.google.common.collect.Lists;
import com.pig4cloud.pig.admin.api.entity.SysUser;
import com.pig4cloud.pig.admin.api.feign.RemoteUserService;
import com.pig4cloud.pig.ads.dao.AdMaterialReportDao;
import com.pig4cloud.pig.ads.pig.mapper.AdMaterialMapper;
import com.pig4cloud.pig.ads.pig.mapper.AdMaterialPlatformMapper;
import com.pig4cloud.pig.ads.pig.mapper.AdOperateMaterialMapper;
import com.pig4cloud.pig.ads.pig.mapper.AdTitleLibMapper;
import com.pig4cloud.pig.ads.pig.mapper.tag.AdTagMapper;
import com.pig4cloud.pig.ads.service.AdAccountService;
import com.pig4cloud.pig.ads.service.AdMaterialCollectService;
import com.pig4cloud.pig.ads.service.AdMaterialCoverService;
import com.pig4cloud.pig.ads.service.AdMaterialPlatformService;
import com.pig4cloud.pig.ads.service.AdMaterialPushWorkerService;
import com.pig4cloud.pig.ads.service.AdMaterialService;
import com.pig4cloud.pig.ads.service.tag.AdTagRelateService;
import com.pig4cloud.pig.ads.utils.DateUtils;
import com.pig4cloud.pig.api.dto.AdMaterialAccount;
import com.pig4cloud.pig.api.dto.AdMaterialDownResp;
import com.pig4cloud.pig.api.dto.AdMaterialResp;
import com.pig4cloud.pig.api.dto.AdMaterialSynResp;
import com.pig4cloud.pig.api.dto.UserByMaterialResp;
import com.pig4cloud.pig.api.entity.AdAccount;
import com.pig4cloud.pig.api.entity.AdMaterial;
import com.pig4cloud.pig.api.entity.AdMaterialCollect;
import com.pig4cloud.pig.api.entity.AdMaterialCover;
import com.pig4cloud.pig.api.entity.AdMaterialPlatform;
import com.pig4cloud.pig.api.entity.AdMaterialPlatformToken;
import com.pig4cloud.pig.api.entity.AdMaterialReportDO;
import com.pig4cloud.pig.api.entity.tag.AdTagList;
import com.pig4cloud.pig.api.entity.tag.BatchSettingTagDto;
import com.pig4cloud.pig.api.util.Constants;
import com.pig4cloud.pig.api.util.UploadUtils;
import com.pig4cloud.pig.api.vo.AdAccountVo;
import com.pig4cloud.pig.api.vo.AdMaterialPageVo;
import com.pig4cloud.pig.api.vo.AdMaterialReportVo;
import com.pig4cloud.pig.api.vo.AdMaterialSearchVo;
import com.pig4cloud.pig.api.vo.AdMaterialVo;
import com.pig4cloud.pig.api.vo.MaterialUserVo;
import com.pig4cloud.pig.api.vo.UserByMaterialVo;
import com.pig4cloud.pig.common.core.constant.SecurityConstants;
import com.pig4cloud.pig.common.core.constant.enums.MaterialTypeEnum;
import com.pig4cloud.pig.common.core.constant.enums.PlatformTypeEnum;
import com.pig4cloud.pig.common.core.exception.CheckedException;
import com.pig4cloud.pig.common.core.util.R;
import com.pig4cloud.pig.common.security.util.SecurityUtils;
import com.tencent.ads.model.VideosUpdateRequest;
import com.tencent.ads.model.VideosUpdateResponseData;

import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;

/**
 * 素材库
 *
 * @date 2021-06-19 16:12:13
 */
@Log4j2
@Service
public class AdMaterialServiceImpl extends ServiceImpl<AdMaterialMapper, AdMaterial> implements AdMaterialService {

	@Autowired
	private AdMaterialMapper adMaterialMapper;
	@Autowired
	private AdMaterialCoverService adMaterialCoverService;
	@Autowired
	private AdMaterialPlatformService adMaterialPlatformService;
	@Autowired
	private RemotePGameService remotePGameService;
	@Autowired
	private AdAccountService adAccountService;
	@Autowired
	private AdMaterialCollectService adMaterialCollectService;
	@Autowired
	private AdMaterialReportDao materialReportDao;
	@Autowired
	private RemoteUserService remoteUserService;
	@Autowired
	private AdTitleLibMapper adTitleLibMapper;
	@Autowired
	private AdOperateMaterialMapper adOperateMaterialMapper;
	@Autowired
	private AdMaterialPlatformMapper adMaterialPlatformMapper;
	@Autowired
	private AdTagMapper adTagMapper;
	@Autowired
	private AdTagRelateService adTagRelateService;
	@Autowired
	private AdMaterialPushWorkerService adMaterialPushWorker;
	
	/**
	 * 上传地址
	 */
	@Value("${video_download_url}")
	private String downloadUrl;
	/**
	 * 下载地址
	 */
	@Value("${video_upload_path}")
	private String uploadPath;
	/**
	 * 限制大小
	 */
	@Value("${video_size}")
	private String size;
	
	
	/**
	 * presto 数据源配置
	 */
	@Value(value = "${ch_3399_schema}")
	private String clickhouse;
	@Value(value = "${pig_schema}")
	private String pigSchema;
	
	


	/**
	 * 人物类型 --1：视频素材-创意者 2 ：视频素材-制作者 3：平面素材-创意者 4：平面素材-制作者 5：运营素材-创意者
	 * 6：运营素材-制作者 7：素材禁用列表-创意者 8：素材禁用列表-制作者 9：文案库-创建人 10：个人素材-创意者
	 * 11：个人素材-制作者 12-视频数据报表-创意者 13-视频数据报表-制作者 14：素材数据报表-创意者 15：素材数据报表-制作者
	 * @Description:
	 * @Author: zjz
	 * @Date: 2022/7/6
	 */
	@Override
	public R getUserByMaterial(UserByMaterialVo req){
		List<Integer> ids = new ArrayList<>();

		MaterialUserVo materialUserVo = new MaterialUserVo();
		List<UserByMaterialResp> ulist;
		switch (req.getCharacterType()){
			case 1:
				materialUserVo.setPtype("2");
				materialUserVo.setType("1");
				materialUserVo.setStatus("0");
				materialUserVo.setIsDelete("0");
				materialUserVo.setReadpop("0");
				ulist = adMaterialMapper.getUserByMaterial(materialUserVo);
				ids = ulist.stream().map(UserByMaterialResp::getUserId).collect(Collectors.toList());
				break;
			case 2:
				materialUserVo.setPtype("1");
				materialUserVo.setType("1");
				materialUserVo.setStatus("0");
				materialUserVo.setIsDelete("0");
				materialUserVo.setReadpop("0");
				ulist = adMaterialMapper.getUserByMaterial(materialUserVo);
				ids = ulist.stream().map(UserByMaterialResp::getUserId).collect(Collectors.toList());
				break;
			case 3:
				materialUserVo.setPtype("2");
				materialUserVo.setType("2");
				materialUserVo.setStatus("0");
				materialUserVo.setIsDelete("0");
				materialUserVo.setReadpop("0");
				ulist = adMaterialMapper.getUserByMaterial(materialUserVo);
				ids = ulist.stream().map(UserByMaterialResp::getUserId).collect(Collectors.toList());
				break;
			case 4:
				materialUserVo.setPtype("1");
				materialUserVo.setType("2");
				materialUserVo.setStatus("0");
				materialUserVo.setIsDelete("0");
				materialUserVo.setReadpop("0");
				ulist = adMaterialMapper.getUserByMaterial(materialUserVo);
				ids = ulist.stream().map(UserByMaterialResp::getUserId).collect(Collectors.toList());
				break;
			case 5:
				materialUserVo.setPtype("2");
				materialUserVo.setIsDelete("0");
				ulist = adOperateMaterialMapper.getUserByMaterial(materialUserVo);
				ids = ulist.stream().map(UserByMaterialResp::getUserId).collect(Collectors.toList());
				break;
			case 6:
				materialUserVo.setPtype("1");
				materialUserVo.setIsDelete("0");
				ulist = adOperateMaterialMapper.getUserByMaterial(materialUserVo);
				ids = ulist.stream().map(UserByMaterialResp::getUserId).collect(Collectors.toList());
				break;
			case 7:
				materialUserVo.setPtype("2");
				materialUserVo.setStatus("1");
				materialUserVo.setIsDelete("0");
				ulist = adMaterialMapper.getUserByMaterial(materialUserVo);
				ids = ulist.stream().map(UserByMaterialResp::getUserId).collect(Collectors.toList());
				break;
			case 8:
				materialUserVo.setPtype("1");
				materialUserVo.setStatus("1");
				materialUserVo.setIsDelete("0");
				ulist = adMaterialMapper.getUserByMaterial(materialUserVo);
				ids = ulist.stream().map(UserByMaterialResp::getUserId).collect(Collectors.toList());
				break;
			case 9:
				ulist = adTitleLibMapper.getCreateuser();
				ids = ulist.stream().map(UserByMaterialResp::getUserId).collect(Collectors.toList());
				break;
			case 10:
				materialUserVo.setPtype("2");
				materialUserVo.setStatus("0");
				materialUserVo.setIsCollect("true");
				materialUserVo.setLoginUserId(String.valueOf(Objects.requireNonNull(SecurityUtils.getUser()).getId()));
				materialUserVo.setIsDelete("0");
				ulist = adMaterialMapper.getUserByMaterial(materialUserVo);
				ids = ulist.stream().map(UserByMaterialResp::getUserId).collect(Collectors.toList());
				break;
			case 11:
				materialUserVo.setPtype("1");
				materialUserVo.setStatus("0");
				materialUserVo.setIsCollect("true");
				materialUserVo.setLoginUserId(String.valueOf(Objects.requireNonNull(SecurityUtils.getUser()).getId()));
				materialUserVo.setIsDelete("0");
				ulist = adMaterialMapper.getUserByMaterial(materialUserVo);
				ids = ulist.stream().map(UserByMaterialResp::getUserId).collect(Collectors.toList());
				break;
			case 12:
				materialUserVo.setPtype("2");
				materialUserVo.setType("1");
				ulist = adMaterialMapper.getUserByMaterial(materialUserVo);
				ids = ulist.stream().map(UserByMaterialResp::getUserId).collect(Collectors.toList());
				break;
			case 13:
				materialUserVo.setPtype("1");
				materialUserVo.setType("1");
				ulist = adMaterialMapper.getUserByMaterial(materialUserVo);
				ids = ulist.stream().map(UserByMaterialResp::getUserId).collect(Collectors.toList());
				break;
			case 14:
				materialUserVo.setPtype("2");
				ulist = adMaterialMapper.getUserByMaterial(materialUserVo);
				ids = ulist.stream().map(UserByMaterialResp::getUserId).collect(Collectors.toList());
				break;
			case 15:
				materialUserVo.setPtype("1");
				ulist = adMaterialMapper.getUserByMaterial(materialUserVo);
				ids = ulist.stream().map(UserByMaterialResp::getUserId).collect(Collectors.toList());
				break;
			default:
				break;
		}
		if(CollectionUtils.isEmpty(ids)){
			return R.ok(new ArrayList<>());
		}
		R<List<SysUser>> userList = remoteUserService.getUserListByUserIds(SecurityConstants.FROM_IN, ids);
		List<UserByMaterialResp> list = new ArrayList<>();
		if (userList != null && CollectionUtils.isNotEmpty(userList.getData())) {
			userList.getData().forEach(a->{
				UserByMaterialResp userByMaterialResp= new UserByMaterialResp();
				userByMaterialResp.setUserId(a.getUserId());
				userByMaterialResp.setRealName(a.getRealName());
				list.add(userByMaterialResp);
			});
		}
		return R.ok(list);
	}


	/**
	 * 素材 - 分页
	 *
	 * @param req
	 * @return
	 */
	@Override
	public R getPage(AdMaterialPageVo req) {
		if(StringUtils.isNotBlank(req.getTagIds())){
			req.setTagIdList(Arrays.stream(req.getTagIds().split(",")).map(Long::valueOf).collect(Collectors.toList()));
		}

		req.setLoginUserId(String.valueOf(Objects.requireNonNull(SecurityUtils.getUser()).getId()));
		IPage<AdMaterialResp> iPage = adMaterialMapper.selectByPage(req);

		List<AdMaterialResp> list = iPage.getRecords();
		if (CollectionUtils.isNotEmpty(list)){
			// 处理数据
			this.dealData(list);
			iPage.setRecords(list);
		}

		return R.ok(iPage);
	}

	/**
	 * 素材 - 不分页
	 *
	 * @param req
	 * @return
	 */
	@Override
	public R getList(AdMaterialVo req) {
		req.setLoginUserId(String.valueOf(SecurityUtils.getUser().getId()));
		List<AdMaterialResp> list = adMaterialMapper.selectByPage(req);
		// 处理数据
		this.dealData(list);

		return R.ok(list);
	}

	/**
	 * 素材 - 下拉框
	 * @param req
	 * @return
	 */
	@Override
	public R getDownList(AdMaterialVo req) {
		List<AdMaterialDownResp> list = this.list(Wrappers.<AdMaterial>lambdaQuery()
				.like(StringUtils.isNotBlank(req.getName()),AdMaterial::getName, req.getName())
				.eq(AdMaterial::getType, StringUtils.isBlank(req.getType()) ? 1 : req.getType()).eq(AdMaterial::getIsDelete, 0)
				.eq(AdMaterial::getReadpop, 0).eq(AdMaterial::getStatus, 0)
				.orderByDesc(AdMaterial::getId)
				.last("LIMIT 100"))
				.stream().map(item ->{
					AdMaterialDownResp res = new AdMaterialDownResp();
					res.setId(item.getId());
					res.setName(item.getName());
					return res;
				}).collect(Collectors.toList());
			return R.ok(list);
	}

	/**
	 * 编辑
	 *
	 * @param req
	 * @return
	 */
	@Override
	public R edit(AdMaterialVo req) {
		String ymPath = DateUtils.dateToString(new Date(), DateUtils.YYYYMMDD) + "/";
		String upPath = uploadPath + ymPath;
		String downUrl = downloadUrl + ymPath;
		String vSize = size;

		AdMaterial adMaterial = new AdMaterial();
		adMaterial.setId(Long.valueOf(req.getId()));
		adMaterial.setMainGameId(Integer.valueOf(req.getMainGameId()));
		adMaterial.setCreatorId(Integer.valueOf(req.getCreatorId()));
		adMaterial.setMakerId(Integer.valueOf(req.getMakerId()));
		adMaterial.setMakeType(Integer.valueOf(req.getMakeType()));
		adMaterial.setUpdateUser(String.valueOf(Objects.requireNonNull(SecurityUtils.getUser()).getId()));
		adMaterial.setUpdateTime(new Date());
		if (StringUtils.isNotBlank(req.getNames())) {
			String filename = req.getNames();
			adMaterial.setName(filename);
			String suffix = filename.substring(filename.lastIndexOf(Constants.POINT) + 1).toLowerCase();
			if(UploadUtils.getIsVideo(suffix)){
				adMaterial.setType(MaterialTypeEnum.VIDEO.getType());
			}
			if(UploadUtils.getIsImg(suffix)){
				adMaterial.setType(MaterialTypeEnum.IMAGE.getType());
			}
		}


		try {
			Collection<MultipartFile> files = req.getFiles();
			if (null != files) {
				int num = 0;
				String[] nameArr = req.getNames().split(",");
				for (MultipartFile file : files) {
					// 获取名称
					String filename = file.getOriginalFilename();
					// 获取后缀名
					String suffix = "";
					if(StringUtils.isNotBlank(filename)) {
						suffix = filename.substring(filename.lastIndexOf(Constants.POINT) + 1).toLowerCase();
					}
					Map<String, Object> resultMap ;
					List<Map<String, Object>> videoImgList = Lists.newLinkedList();

					if (UploadUtils.getIsVideo(suffix)) {
						// 上传视频素材
						resultMap = UploadUtils.videoUpload(file, upPath, Long.parseLong(vSize));
						if (0 != Integer.parseInt(String.valueOf(resultMap.get("code")))) {
							return R.failed(resultMap.get("msg"));
						}

						if (null == resultMap.get("videoImgList")) {
							log.error("截取视频封面异常");
							return R.failed("截取视频封面异常");
						}
						videoImgList = (List<Map<String, Object>>) resultMap.get("videoImgList");
						// 素材类型  1：视频，2：图片
						adMaterial.setType(MaterialTypeEnum.VIDEO.getType());
						// 封面图片访问url
						adMaterial.setImageUrl(downUrl + videoImgList.get(0).get("imageName"));
						// 视频时长
						adMaterial.setDuration(String.valueOf(resultMap.get("duration")));
						//尺寸类型
						adMaterial.setScreenType(Integer.parseInt(resultMap.get("screenType").toString()));

					} else if (UploadUtils.getIsImg(suffix)) {
						// 上传图片素材
						resultMap = UploadUtils.imageUpload(upPath, file, Long.parseLong(vSize));
						if (0 != Integer.parseInt(String.valueOf(resultMap.get("code")))) {
							return R.failed(resultMap.get("msg"));
						}
						// 素材类型  1：视频，2：图片
						adMaterial.setType(MaterialTypeEnum.IMAGE.getType());
						// 封面图片访问url
						adMaterial.setImageUrl(downUrl + resultMap.get("filename"));
						//尺寸类型
						adMaterial.setScreenType(this.getPicType(String.valueOf(resultMap.get("width")), String.valueOf(resultMap.get("height"))));

					} else {
						return R.failed("未知的素材类型");
					}
					String name = nameArr[num];
					if (name.contains(Constants.POINT)) {
						name = name.substring(0, name.lastIndexOf(Constants.POINT));
					}
					//名称
					adMaterial.setName(name + Constants.POINT + suffix);
					//文件名称
					adMaterial.setFileName(String.valueOf(resultMap.get("filename")));
					//访问url
					adMaterial.setFileUrl(downUrl + resultMap.get("filename"));
					//宽
					adMaterial.setWidth(String.valueOf(resultMap.get("width")));
					//高
					adMaterial.setHeight(String.valueOf(resultMap.get("height")));
					//大小
					adMaterial.setSize(String.valueOf(resultMap.get("size")));
					//格式
					adMaterial.setFormat(String.valueOf(resultMap.get("format")));
					//真实路径
					adMaterial.setRealPath(String.valueOf(resultMap.get("realPath")));
					//md5值
					String md5 = DigestUtils.md5Hex(file.getInputStream());
					adMaterial.setMd5(md5);
					//主游戏
					adMaterial.setMainGameId(Integer.valueOf(req.getMainGameId()));
					//创意者
					adMaterial.setCreatorId(Integer.valueOf(req.getCreatorId()));
					//制作者
					adMaterial.setMakerId(Integer.valueOf(req.getMakerId()));
					//制作类型
					adMaterial.setMakeType(Integer.valueOf(req.getMakeType()));

					// 保存视频封面
					if (MaterialTypeEnum.VIDEO.getType().equals(adMaterial.getType())) {
						QueryWrapper<AdMaterialCover> wrapper = new QueryWrapper<>();
						wrapper.eq("material_id", adMaterial.getId());
						// 删除已有视频封面图片
						adMaterialCoverService.remove(wrapper);
						// 保存视频封面图片
						saveVideoImg(videoImgList, adMaterial, upPath, downUrl);
					}

					num++;
				}
			}else {
				ExecutorService es = new ThreadPoolExecutor(5, 5, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<>(50));
				es.submit(() -> {
					AdMaterial adMaterialhis = this.getById(adMaterial.getId());
					if (MaterialTypeEnum.VIDEO.getType().equals(adMaterialhis.getType()) && !adMaterialhis.getName().equals(adMaterial.getName())) {
						//判断是否推送
						List<Long> listIds = new ArrayList<>();
						listIds.add(adMaterial.getId());
						List<AdMaterialPlatformToken> ampList = adMaterialPlatformMapper.getListByMidToken(listIds);
						ampList.forEach(a -> {
							switch (Objects.requireNonNull(PlatformTypeEnum.getByValue(a.getPlatformId() + ""))) {
								case TT:
									this.editTt(a,adMaterial.getName());
									break;
								case GDT:
									this.editGdt(a,adMaterial.getName());
									break;
								case KS:
									this.editKs(a,adMaterial.getName());
									break;
								default:
									break;
							}

						});
					}
				});
			}
			// 修改素材信息

			boolean flag = this.updateById(adMaterial);
			BatchSettingTagDto dto = new BatchSettingTagDto();
			dto.setType(adMaterial.getType());
			dto.setRelateIds(req.getId()+"");
			dto.setTagIds(req.getTagIds());
			adTagRelateService.batchSettingTag(dto);

			if (flag) {
				log.info(adMaterial.getName() + "上传成功");
				return R.ok(adMaterial);
			}
		} catch (Exception e) {
			e.printStackTrace();
			log.error("文件上传失败：{}", e.getMessage());
			return R.failed(null, "文件上传失败");
		}
		return R.failed();
	}

	/**
	 * 修改素材名称
	 * @param req
	 * @return
	 */
	@SneakyThrows
	private void editTt(AdMaterialPlatformToken req, String name) {
		if(StringUtils.isBlank(req.getTtAccessToken())){
			log.info("头条修改视频名称：AccessToken is null");
			return;
		}
		DyTtClient ttClient = new DyTtClient("");
		TtVideoUpdateRequest appListRequest = new TtVideoUpdateRequest();
		appListRequest.setAdvertiser_id(Long.parseLong(req.getAdvertiserId()));
		VideoUpdate videoUpdate= new VideoUpdate();
		videoUpdate.setFilename(name);
		videoUpdate.setVideo_id(req.getPlatformFileId());
		List<VideoUpdate> list = new ArrayList<>();
		list.add(videoUpdate);
		appListRequest.setVideos(list);
		String result = ttClient.call4Post(appListRequest, req.getTtAccessToken());
		log.info("头条修改视频名称：{}",result);
	}

	/**
	 * 修改素材名称
	 * @param req
	 * @return
	 */
	@SneakyThrows
	private void editGdt(AdMaterialPlatformToken req, String name) {
		try {
			if(StringUtils.isBlank(req.getGdtAccessToken())){
				log.info("广点通修改视频名称：AccessToken is null");
				return;
			}
			DyGdtClient dyGdtClient = new DyGdtClient();
			VideosUpdateRequest videosUpdateRequest = new VideosUpdateRequest();
			videosUpdateRequest.setAccountId(Long.parseLong(req.getAdvertiserId()));
			videosUpdateRequest.setVideoId(Long.parseLong(req.getPlatformMaterialId()));
			videosUpdateRequest.setDescription(name);
			VideosUpdateResponseData result = dyGdtClient.getTencentAds(req.getGdtAccessToken()).videos().videosUpdate(videosUpdateRequest);
			String resultString = result !=null ? JSON.toJSONString(result):"空";
			log.info("广点通修改视频名称：{}",resultString);
		}catch (Exception e){
			log.info("广点通修改视频名称异常：{}",e.getMessage());
		}
	}

	/**
	 * 快手修改视频名称
	 * @param req
	 * @return
	 */
	@SneakyThrows
	private void editKs(AdMaterialPlatformToken req, String name) {
		if(StringUtils.isBlank(req.getKsAccessToken())){
			log.info("快手修改视频名称：AccessToken is null");
			return;
		}
		DyKsClient ksClient = new DyKsClient("");
		KsVideoUpdateRequest request  = new KsVideoUpdateRequest();
		request.setAdvertiser_id(Long.parseLong(req.getAdvertiserId()));
		request.setPhoto_ids(new String[]{req.getPlatformMaterialId()});
		request.setPhoto_name(name);
		String result = ksClient.call4Post(request,req.getKsAccessToken());
		log.info("快手修改视频名称：{}",result);
	}


	/**
	 * 删除
	 *
	 * @param req
	 * @return
	 */
	@Override
	public R del(AdMaterialVo req) {
		QueryWrapper<AdMaterial> wrapper = new QueryWrapper<>();
		wrapper.apply("id in ( " + req.getIds() + " )");
		AdMaterial adMaterial = new AdMaterial();
		adMaterial.setIsDelete(1);
		boolean flag = this.update(adMaterial, wrapper);
		if (flag) {
			return R.ok("删除成功");
		}
		return R.failed();
	}

	/**
	 * 根据id查询素材信息
	 *
	 * @param req
	 * @return
	 */
	@Override
	public R findById(AdMaterialVo req) {
		AdMaterialSynResp adMaterialResp = adMaterialMapper.selectByPlatformFileId(req);
		return R.ok(adMaterialResp);
	}

	/**
	 * 添加收藏
	 *
	 * @param req
	 * @return
	 */
	@Override
	public R addCollect(AdMaterialVo req) {
		// 验证素材是否已经收藏
		QueryWrapper<AdMaterialCollect> wrapper = new QueryWrapper<>();
		wrapper.eq("user_id", SecurityUtils.getUser().getId());
		wrapper.eq("material_id", req.getId());
		int count = adMaterialCollectService.count(wrapper);
		if (count > 0) {
			return R.failed("此素材已经被收藏");
		}

		AdMaterialCollect adMaterialCollect = new AdMaterialCollect();
		adMaterialCollect.setUserId(SecurityUtils.getUser().getId());
		adMaterialCollect.setMaterialId(Integer.valueOf(req.getId()));
		adMaterialCollect.setCreateTime(new Date());
		boolean flag = adMaterialCollectService.save(adMaterialCollect);
		if (flag) {
			return R.ok("收藏成功");
		}
		return R.failed();
	}

	/**
	 * 删除收藏
	 *
	 * @param req
	 * @return
	 */
	@Override
	public R delCollect(AdMaterialVo req) {
		QueryWrapper<AdMaterialCollect> wrapper = new QueryWrapper<>();
		wrapper.eq("user_id", SecurityUtils.getUser().getId());
		wrapper.apply("material_id in ( " + req.getIds() + " )");
		boolean flag = adMaterialCollectService.remove(wrapper);
		if (flag) {
			String[] ids = req.getIds().split(",");
			for (String id : ids) {
				AdMaterial adMaterial = this.getById(id);
				// 删除收藏，如果文件为私有并且是自己上传的素材，同时删除素材
				if (1 == adMaterial.getReadpop() && adMaterial.getCreateUser().equals(String.valueOf(SecurityUtils.getUser().getId()))) {
					this.removeById(id);
				}
			}
			return R.ok("删除成功");
		}
		return R.failed();
	}

	/**
	 * 返回数据处理
	 *
	 * @param adMaterialRespList
	 */
	private void dealData(List<AdMaterialResp> adMaterialRespList) {
		if (CollectionUtils.isNotEmpty(adMaterialRespList)) {
			Collection<Long> gameIds = adMaterialRespList.stream().map(item -> Long.valueOf(String.valueOf(item.getMainGameId()))).collect(Collectors.toSet());

			// 获取标签列表
			Set<Long> setId = new HashSet<>();
			adMaterialRespList.stream().filter(n->StringUtils.isNotBlank(n.getTagIds())).forEach(a-> setId.addAll(Arrays.stream(a.getTagIds().split(",")).map(Long::valueOf).collect(Collectors.toList())));
			List<AdTagList> taglistDate = CollectionUtils.isNotEmpty(setId)? adTagMapper.tagListByIds(new ArrayList<>(setId)):new ArrayList<>();
			Map<Long,AdTagList> map = taglistDate.stream().collect(Collectors.toMap(AdTagList::getId,a->a));

			// 获取父游戏列表
			R<List<ParentGameDO>> gameListData = remotePGameService.getCacheablePGameList(new ParentGameReq().setIds(gameIds));
			List<ParentGameDO> gameList = gameListData.getData();
			// 获取当前账号的广告账户
			List<AdAccount> adAccountList = adAccountService.getListByAccount(new AdAccountVo());
			List<Long> listMid = adMaterialRespList.stream().map(AdMaterialResp::getId).collect(Collectors.toList());
			List<AdMaterialPlatform> ampList = adMaterialPlatformMapper.getListByMid(listMid);
			for (AdMaterialResp adMaterialResp : adMaterialRespList) {
				List<AdMaterialAccount> pushTtList = Lists.newLinkedList();
				List<AdMaterialAccount> pushGdtList = Lists.newLinkedList();
				List<AdMaterialAccount> pushKsList = Lists.newLinkedList();
				// 翻译父游戏名称
				if (CollectionUtils.isNotEmpty(gameList)) {
					gameList.forEach(game -> {
						if (adMaterialResp.getMainGameId() == game.getId().intValue()) {
							adMaterialResp.setMainGameName(game.getGname());
						}
					});
				}
				List<AdMaterialPlatform>  adMpList = ampList.stream().filter(a->a.getMaterialId().equals(adMaterialResp.getId())).collect(Collectors.toList());
				// 广告账户同步状态
				if (CollectionUtils.isNotEmpty(adAccountList)) {
					HashSet<String> ttSynNums = new HashSet<>();
					HashSet<String> gdtSynNums = new HashSet<>();
					HashSet<String> ksSynNums = new HashSet<>();
					for (AdAccount adAccount : adAccountList) {
						AdMaterialAccount ama = new AdMaterialAccount();
						ama.setAdvertiserId(adAccount.getAdvertiserId());
						ama.setAdvertiserName(adAccount.getAdvertiserName());
						ama.setSyn(0);
						if (CollectionUtils.isEmpty(adMpList)) {
							continue;
						}
						for (AdMaterialPlatform adMaterialPlatform : adMpList) {
							if (!adMaterialPlatform.getAdvertiserId().equals(adAccount.getAdvertiserId())||!adAccount.getMediaCode().equals(adMaterialPlatform.getPlatformId()+"")) {
								continue;
							}
							ama.setSyn(1);
							if (PlatformTypeEnum.TT.getValue().equals(adMaterialPlatform.getPlatformId()+"")) {
								ttSynNums.add(adMaterialPlatform.getAdvertiserId());
							} else if (PlatformTypeEnum.GDT.getValue().equals(adMaterialPlatform.getPlatformId()+"")) {
								gdtSynNums.add(adMaterialPlatform.getAdvertiserId());
							}else if (PlatformTypeEnum.KS.getValue().equals(adMaterialPlatform.getPlatformId()+"")) {
								ksSynNums.add(adMaterialPlatform.getAdvertiserId());
							}
						}
						if (PlatformTypeEnum.TT.getValue().equals(adAccount.getMediaCode())) {
							pushTtList.add(ama);
						} else if (PlatformTypeEnum.GDT.getValue().equals(adAccount.getMediaCode())) {
							pushGdtList.add(ama);
						} else if (PlatformTypeEnum.KS.getValue().equals(adAccount.getMediaCode())) {
							pushKsList.add(ama);
						}
					}
					adMaterialResp.setTtSynStatus(synStatusDeal(ttSynNums.size(),pushTtList.size()));
					adMaterialResp.setGdtSynStatus(synStatusDeal(gdtSynNums.size(),pushGdtList.size()));
					adMaterialResp.setKsSynStatus(synStatusDeal(ksSynNums.size(),pushKsList.size()));
				}
				adMaterialResp.setPushTtList(pushTtList);
				adMaterialResp.setPushGdtList(pushGdtList);
				adMaterialResp.setPushKsList(pushKsList);
				// 标签
				List<AdTagList> taglist = new ArrayList<>();
				if (map.size() > 0&&StringUtils.isNotBlank(adMaterialResp.getTagIds())){
					Arrays.stream(adMaterialResp.getTagIds().split(",")).forEach(c-> taglist.add(map.get(Long.valueOf(c))));
				}
				adMaterialResp.setTagList(taglist);
			}
		}
	}

	/**
	 * @Description: 同步状态：0：未同步，1：部分同步，2：全部同步
	 * @Author: zjz
	 * @Date: 2022/8/8
	 */
	private int synStatusDeal(Integer num,Integer size){
		int re = 0;
		if (num == 0) {
			return re;
		} else if (num < size) {
			re = 1;
		} else if (num.equals(size)) {
			re = 2;
		}
		return  re;
	}

	/**
	 * 添加素材
	 *
	 * @param req
	 * @return
	 */
	@Override
	public R addMaterial(AdMaterialVo req) {
		String ymPath = DateUtils.dateToString(new Date(), DateUtils.YYYYMMDD) + "/";
		String upPath = uploadPath + ymPath;
		String downUrl = downloadUrl + ymPath;
		String vSize = size;
		List<AdMaterial> adMaterialList = Lists.newLinkedList();
		try {
			Collection<MultipartFile> files = req.getFiles();
			if (null != files) {
				AdMaterial adMaterialParam = new AdMaterial();
				adMaterialParam.setCreateTime(new Date());
				adMaterialParam.setUpdateTime(new Date());
				// 炎帝推送素材到盘古，因为feign调用登陆状态丢失，所以用户ID传过来
				if (StringUtils.isNotBlank(req.getUserId())) {
					adMaterialParam.setCreateUser(req.getUserId());
					adMaterialParam.setUpdateUser(req.getUserId());
				} else {
					adMaterialParam.setCreateUser(String.valueOf(SecurityUtils.getUser().getId()));
					adMaterialParam.setUpdateUser(String.valueOf(SecurityUtils.getUser().getId()));
				}

				int num = 0;
				String[] nameArr = req.getNames().split(",");
				for (MultipartFile file : files) {
					// 获取名称
					String filename = file.getOriginalFilename();
					String suffix="";
					if(StringUtils.isNotBlank(filename)){
						// 获取后缀名
						suffix = filename.substring(filename.lastIndexOf(Constants.POINT) + 1).toLowerCase();
					}
					Map<String, Object> resultMap;
					List<Map<String, Object>> videoImgList = Lists.newLinkedList();

					if (UploadUtils.getIsVideo(suffix)) {
						// 上传视频素材
						resultMap = UploadUtils.videoUpload(file, upPath, Long.parseLong(vSize));
						if ( 0 != Integer.parseInt(String.valueOf(resultMap.get("code")))) {
							return R.failed(resultMap.get("msg"));
						}
						if (Double.valueOf(String.valueOf(resultMap.get("duration"))) < 4) {
							return R.failed(null, "视频时长不能小于4秒");
						}
						if (null == resultMap.get("videoImgList")) {
							log.error("截取视频封面异常");
							return R.failed("截取视频封面异常");
						}
						videoImgList = (List<Map<String, Object>>) resultMap.get("videoImgList");
						// 素材类型  1：视频，2：图片
						adMaterialParam.setType(MaterialTypeEnum.VIDEO.getType());
						// 封面图片访问url
						adMaterialParam.setImageUrl(downUrl + videoImgList.get(0).get("imageName"));
						// 视频时长
						adMaterialParam.setDuration(String.valueOf(resultMap.get("duration")));
						//尺寸类型
						adMaterialParam.setScreenType(Integer.parseInt(resultMap.get("screenType").toString()));

					} else if (UploadUtils.getIsImg(suffix)) {
						// 上传图片素材
						resultMap = UploadUtils.imageUpload(upPath, file, Long.parseLong(vSize));
						if (0 != Integer.parseInt(String.valueOf(resultMap.get("code")))) {
							return R.failed(resultMap.get("msg"));
						}
						// 素材类型  1：视频，2：图片
						adMaterialParam.setType(MaterialTypeEnum.IMAGE.getType());
						// 封面图片访问url
						adMaterialParam.setImageUrl(downUrl + resultMap.get("filename"));
						//尺寸类型
						adMaterialParam.setScreenType(this.getPicType(String.valueOf(resultMap.get("width")), String.valueOf(resultMap.get("height"))));

					} else {
						return R.failed("未知的素材类型");
					}

					String name = nameArr[num];
					if (name.contains(Constants.POINT)) {
						name = name.substring(0, name.lastIndexOf(Constants.POINT));
					}
					//名称
					adMaterialParam.setName(name + Constants.POINT + suffix);
					//文件名称
					adMaterialParam.setFileName(String.valueOf(resultMap.get("filename")));
					//访问url
					adMaterialParam.setFileUrl(downUrl + resultMap.get("filename"));
					//宽
					adMaterialParam.setWidth(String.valueOf(resultMap.get("width")));
					//高
					adMaterialParam.setHeight(String.valueOf(resultMap.get("height")));
					//大小
					adMaterialParam.setSize(String.valueOf(resultMap.get("size")));
					//格式
					adMaterialParam.setFormat(String.valueOf(resultMap.get("format")));
					//真实路径
					adMaterialParam.setRealPath(String.valueOf(resultMap.get("realPath")));
					//md5值
					String md5 = DigestUtils.md5Hex(file.getInputStream());
					adMaterialParam.setMd5(md5);
					//主游戏
					adMaterialParam.setMainGameId(Integer.valueOf(req.getMainGameId()));
					//创意者
					adMaterialParam.setCreatorId(Integer.valueOf(req.getCreatorId()));
					//制作者
					adMaterialParam.setMakerId(Integer.valueOf(req.getMakerId()));
					//制作类型
					adMaterialParam.setMakeType(Integer.valueOf(req.getMakeType()));
					//卖点
					adMaterialParam.setSellingPointId(req.getSellingPointId());
					//素材来源：0：盘古；1：炎帝
					adMaterialParam.setOrigin(req.getOrigin());
					//业务ID
					adMaterialParam.setOriginId(req.getOriginId());
					// 收藏列表上传的为私有素材
					if ("true".equals(req.getIsCollect())) {
						adMaterialParam.setReadpop(1);
					}
					// 保存素材
					boolean flag = this.save(adMaterialParam);
					if (flag) {
						adMaterialList.add(adMaterialParam);
						if (MaterialTypeEnum.VIDEO.getType().intValue() == adMaterialParam.getType()) {
							//保存视频图片
							saveVideoImg(videoImgList, adMaterialParam, upPath, downUrl);
						}
						log.info(adMaterialParam.getName() + "上传成功");
					}
					num++;

					// 添加收藏 （收藏列表上传的为私有素材）
					if ("true".equals(req.getIsCollect())) {
						AdMaterialCollect adMaterialCollect = new AdMaterialCollect();
						adMaterialCollect.setUserId(SecurityUtils.getUser().getId());
						adMaterialCollect.setMaterialId(adMaterialParam.getId().intValue());
						adMaterialCollect.setCreateTime(new Date());
						adMaterialCollectService.save(adMaterialCollect);
					}
					if(StringUtils.isNotBlank(req.getTagIds())){
						BatchSettingTagDto dto = new BatchSettingTagDto();
						dto.setType(adMaterialParam.getType());
						dto.setRelateIds(adMaterialParam.getId()+"");
						dto.setTagIds(req.getTagIds());
						adTagRelateService.batchSettingTag(dto);
					}
				}
			} else {
				log.error("未获取到素材文件");
				return R.failed("未获取到素材文件");
			}
		} catch (Exception e) {
			e.printStackTrace();
			log.error("文件上传失败：{}", e);
			return R.failed(null, "文件上传失败");
		}
		return R.ok(adMaterialList);
	}

	/**
	 * 视频封面图批量插入图片库
	 *
	 * @param videoImgList
	 * @param adMaterial
	 * @param upPath
	 * @param downUrl
	 * @return
	 */
	public R saveVideoImg(List<Map<String, Object>> videoImgList, AdMaterial adMaterial, String upPath, String downUrl) throws IOException {
		if (CollectionUtils.isNotEmpty(videoImgList)) {
			List<AdMaterialCover> materialCoverArrayList = Lists.newArrayList();
			for (Map<String, Object> map : videoImgList) {
				//String md5 = DigestUtils.md5Hex(upPath + map.get("imageName"));
				String md5 = DigestUtils.md5Hex(new FileInputStream(upPath + map.get("imageName")));
				AdMaterialCover materialCover = new AdMaterialCover();
				materialCover.setMaterialId(adMaterial.getId().intValue());
				materialCover.setFileName(adMaterial.getName() + "_进度" + map.get("videoRate") + "%封面.jpg");
				materialCover.setFileUrl(downUrl + map.get("imageName"));
				materialCover.setRealPath(upPath + map.get("imageName"));
				materialCover.setMd5(md5);
				materialCoverArrayList.add(materialCover);
			}
			adMaterialCoverService.saveBatch(materialCoverArrayList);
		}
		return R.ok();
	}

	/**
	 * 批量推送
	 *
	 * @param req
	 * @return
	 */
	@Override
	@SneakyThrows
	public R pushMaterial(AdMaterialVo req){
		List<AdMaterialPlatform> resultList = Lists.newArrayList();
		List<Long> ids = Arrays.stream(req.getIds().split(",")).map(Long::parseLong).collect(Collectors.toList());
		List<Long> advertiserIds = Arrays.stream(req.getAdvertiserIds().split(",")).map(Long::parseLong).collect(Collectors.toList());
		List<AdMaterialPlatform> adMaterialPlatformList = adMaterialPlatformMapper.getListByMidAndIds(advertiserIds,ids);
		List<AdMaterial> adMaterialList = this.listByIds(ids);
		if(adMaterialList.size()!=ids.size()){
			return R.failed("未获取到素材信息");
		}
		resultList.addAll(adMaterialPlatformList);
		HashSet<String> adList = new HashSet<>();
		adMaterialPlatformList.forEach(a-> adList.add(a.getAdvertiserId()));
		//全部都同步直接返回
		if(adList.size()==advertiserIds.size()*ids.size()) {
			return R.ok(resultList);
		}
		
		List<AdMaterialPlatform> adMaterialPlatformSave = new ArrayList<>();
		String loginUserId  = String.valueOf(SecurityUtils.getUser().getId());
		adMaterialList.forEach(adMaterial -> advertiserIds.stream().filter(b-> !adList.contains(b+"")).forEach(advertiserId -> {
			AdMaterialPlatform adMaterialPlatform;
			switch (Objects.requireNonNull(PlatformTypeEnum.getByValue(req.getPlatformId()))){
				case TT:
					adMaterialPlatform = MaterialTypeEnum.VIDEO.getType().intValue() == adMaterial.getType()?
							adMaterialPushWorker.pushVideoToutiao(loginUserId,advertiserId.toString(), adMaterial) : adMaterialPushWorker.pushPictureToutiao(loginUserId,advertiserId.toString(), adMaterial);
					break;
				case GDT:
					adMaterialPlatform = MaterialTypeEnum.VIDEO.getType().intValue() == adMaterial.getType()?
							adMaterialPushWorker.pushVideoGdt(loginUserId,advertiserId.toString(), adMaterial) : adMaterialPushWorker.pushPictureGdt(loginUserId,advertiserId.toString(), adMaterial);
					break;
				case KS:
					adMaterialPlatform = MaterialTypeEnum.VIDEO.getType().intValue() == adMaterial.getType()?
							adMaterialPushWorker.pushVideoKs(loginUserId,advertiserId.toString(), adMaterial) : adMaterialPushWorker.pushPictureKs(loginUserId,advertiserId.toString(), adMaterial);
					break;
				default:
					throw new CheckedException("无效的平台ID");
			}
			adMaterialPlatformSave.add(adMaterialPlatform);
		}));
		resultList.addAll(adMaterialPlatformSave);
		adMaterialPlatformService.saveBatch(adMaterialPlatformSave,1000);
		return R.ok(resultList);
	}

	//获取到图片类型
	private int getPicType(String widthParam, String heightParam) {
		double width = Double.parseDouble(widthParam);
		double height = Double.parseDouble(heightParam);
		double ratio = width / height;
		BigDecimal bRatio = BigDecimal.valueOf(ratio);
		double ratio2 = bRatio.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
		//其他类型：others
		int type = 0;
		if (1.52 == ratio2 && width >= 456 && width <= 1368 && height >= 300 && height <= 900) {
			//小图
			type = 3;
		} else if (1.78 == ratio2 && width >= 1280 && width <= 2560 && height >= 720 && height <= 1440) {
			//横版大图
			type = 4;
		} else if (0.56 == ratio2 && width >= 720 && width <= 1440 && height >= 1280 && height <= 2560) {
			//竖版大图
			type = 5;
		} else if (690 == width && 388 == height) {
			//gif图
			type = 6;
		} else if (108 == width && 108 == height) {
			//卡片主图
			type = 7;
		}
		return type;
	}

	

	

	

	@Resource
	private AdMaterialMapper materialMapper;

	@Override
	public IPage<AdMaterial> pageList(Page<AdMaterial> objectPage, AdMaterialSearchVo searchVo) {
		IPage<AdMaterial> adMaterialIPage = materialMapper.pageList(objectPage, searchVo);
		dealGameName(adMaterialIPage);
		return adMaterialIPage;
	}

	/**
	 * 返回数据处理
	 *
	 * @param iPage
	 */
	public void dealGameName(IPage<AdMaterial> iPage) {
		if (Objects.nonNull(iPage) && CollectionUtils.isNotEmpty(iPage.getRecords())) {
			List<AdMaterial> adMaterialRespList = iPage.getRecords();
			Collection<Long> gameIds = adMaterialRespList.stream().map(item -> Long.valueOf(String.valueOf(item.getMainGameId()))).collect(Collectors.toSet());
			// 获取父游戏列表
			R<List<ParentGameDO>> gameListData = remotePGameService.getCacheablePGameList(new ParentGameReq().setIds(gameIds));
			List<ParentGameDO> gameList = gameListData.getData();
			for (AdMaterial adMaterialResp : iPage.getRecords()) {
				// 翻译父游戏名称
				if (CollectionUtils.isNotEmpty(gameList)) {
					gameList.forEach(game -> {
						if (adMaterialResp.getMainGameId() == game.getId().intValue()) {
							adMaterialResp.setMainGameName(game.getGname());
						}
					});
				}
			}
		}
	}

	/**
	 * 根据素材ID列表查询素材信息
	 *
	 * @param materialIds
	 * @return
	 */
	@Transactional(readOnly = true, rollbackFor = Exception.class)
	@Override
	public List<AdMaterial> getMaterialListByIds(List<Long> materialIds) {
		if (CollectionUtils.isEmpty(materialIds)) {
			return Collections.emptyList();
		}
		return this.list(Wrappers.<AdMaterial>lambdaQuery().in(AdMaterial::getId, materialIds));
	}

	/**
	 * 素材数据报表
	 *
	 * @param amr
	 * @return
	 */
	@Override
	public List<AdMaterialReportDO> getMaterialReportList(AdMaterialReportVo amr) {
		return materialReportDao.queryMaterialReportList(amr);
	}

}
